//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "bootmodmgr.h"
#include <aura.h>
#include <stdio.h>

#define DLL_PROCESS_DETACH 0
#define DLL_PROCESS_ATTACH 1

#define FixMe(statement)

#define INVALID_CURRENT_POS     -2

#define ELASTOS_PATH    "\\Program Files\\Elastos\\"
#define _MAX_PATH     260

ECode CBootModuleMgr::Constructor()
{
    char fileName[_MAX_PATH];
    FILE *fp = NULL;

    for (Int32 i = 0; (i < m_numberOfModules) && (NULL != m_pModInfos[i].szName) ; i++) {
        strcpy(fileName, ELASTOS_PATH); // TODO.
        strcat(fileName, m_pModInfos[i].szName);
        fp = fopen(fileName, "rb");
        if (NULL == fp) {
            return E_FILE_NOT_FOUND;
        }
        fseek(fp, 0, SEEK_END);
        m_pModInfos[i].size  = ftell(fp);
        m_pModInfos[i].pFile = Aura_malloc(m_pModInfos[i].size);
        if (NULL == m_pModInfos[i].pFile) {
            fclose(fp);
            return E_OUT_OF_MEMORY;
        }
        fseek(fp, 0, SEEK_SET);
        fread(m_pModInfos[i].pFile, 1, m_pModInfos[i].size, fp);
        fclose(fp);
    }
    return NOERROR;
}

ECode CBootModuleMgr::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 uNumberOfBytesToRead,
    /* [out] */ MemoryBuf * pData,
    /* [out] */ IEvent **ppCompletionEvent)
{
    FixMe("access denied.");
    return E_ACCESS_DENIED;
}

ECode CBootModuleMgr::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & ebbData,
    /* [out] */ Int32 * puNumberOfBytesWritten,
    /* [out] */ IEvent **ppCompletionEvent)
{
    FixMe("access denied.");
    return E_ACCESS_DENIED;
}

ECode CBootModuleMgr::Control(
    /* [in] */ Int32 nControlCode,
    /* [in] */ const MemoryBuf & ebbInData,
    /* [out] */ MemoryBuf * pOutData,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec = NOERROR;

    switch (nControlCode) {
    case BMCommand_Reset:
        ec = Helper_Reset();
        break;

    case BMCommand_MoveNext:
        ec = Helper_MoveNext();
        break;

    case BMCommand_Current:
        if (NULL == pOutData) {
            ec = E_INVALID_ARGUMENT;
            break;
        }
        pOutData->SetUsed(pOutData->GetCapacity());
        ec = Helper_Current((BMFileInfo *)pOutData->GetPayload());
        break;
    case BMCommand_Delete:
        ec = E_NOT_IMPLEMENTED;
        break;
    case BMCommand_Open:
        if (pOutData == NULL) {
            return E_INVALID_ARGUMENT;
        }
        pOutData->SetUsed(12);
        ec = Helper_GetFileInfo((char *)ebbInData.GetPayload(),
                            (BMFileInfo *)pOutData->GetPayload());
        break;
    case BMCommand_Close:
        break;
    default:
        ec = E_INVALID_OPTIONS;
    }

    return ec;
}

void CBootModuleMgr::Dispose()
{
    for (int i = 0; i < m_numberOfModules; i++) {
        if (NULL != m_pModInfos[i].pFile) {
            Aura_free(m_pModInfos[i].pFile);
        }
    }
    delete this;
}

ECode CBootModuleMgr::Helper_Reset()
{
    m_curIndex = -1;
    return NOERROR;
}

ECode CBootModuleMgr::Helper_MoveNext()
{
    if (INVALID_CURRENT_POS == m_curIndex) {
        return E_INVALID_OPERATION;
    }

    m_curIndex++;
    for (;
        ((m_curIndex < (Int32)m_numberOfModules)
        && (NULL == m_pModInfos[m_curIndex].szName));
        m_curIndex++);

    if (m_curIndex >= (Int32)m_numberOfModules) {
        m_curIndex = INVALID_CURRENT_POS;
        return E_INVALID_OPERATION;
    }
    return NOERROR;
}

ECode CBootModuleMgr::Helper_Current(
    /* [out] */ BMFileInfo *pInfo)
{
    if ((INVALID_CURRENT_POS == m_curIndex)
        || (-1 == m_curIndex)
        || (NULL == m_pModInfos[m_curIndex].szName)) {
        return E_INVALID_OPERATION;
    }

    pInfo->uIndex = (UInt32)m_curIndex;
    pInfo->uUAddr = (UInt32)m_pModInfos[m_curIndex].pFile;
    pInfo->uSize  = (UInt32)m_pModInfos[m_curIndex].size;

    strcpy(pInfo->szName, m_pModInfos[m_curIndex].szName);

    return NOERROR;
}

ECode CBootModuleMgr::Helper_GetFileInfo(
    /* [in] */ char * szName,
    /* [out] */ BMFileInfo *pInfo)
{
    Int32 i = 0;

    assert(NULL != szName);
    assert('\0' != szName[0]);
    assert(NULL != pInfo);

    for (;i < m_numberOfModules; i++) {
        if (!strcmp(szName, m_pModInfos[i].szName)) {
            break;
        }
    }

    if (i >= m_numberOfModules) {
        return E_FILE_NOT_FOUND;
    }

    pInfo->uIndex = i;
    pInfo->uUAddr = (UInt32)m_pModInfos[i].pFile;
    pInfo->uSize = m_pModInfos[i].size;

    return NOERROR;
}

static ModuleInfo s_moduleInfos[] = {
    {"encoding.dat", NULL, 0},
    {NULL,           NULL, 0}
};

static CBootModuleMgr * s_pBootModuleMgr = NULL;

ELAPI _CSystem_RegisterRunningObject(WString name, PInterface pService);

extern "C" ECode BootModuleMgrDriver_Initialize()
{
    CBootModuleMgr * pModuleMgr = NULL;
    Int32 numberOfModules = 0;
    ECode ec = NOERROR;
    numberOfModules = sizeof(s_moduleInfos) / sizeof(ModuleInfo);
    pModuleMgr = new CBootModuleMgr(s_moduleInfos, numberOfModules);
    if (NULL == pModuleMgr) {
        ec = E_OUT_OF_MEMORY;
        goto E_FAIL_EXIT;
    }
    ec = pModuleMgr->Constructor();
    if (FAILED(ec)) {
        goto E_FAIL_EXIT;
    }
    ec =
    pModuleMgr->AddRef();
    s_pBootModuleMgr = pModuleMgr;

    return NOERROR;

E_FAIL_EXIT:
    if (NULL != pModuleMgr) {
        delete pModuleMgr;
    }
    return ec;
}

extern "C"  void  BootModuleMgrDriver_Destroy()
{
    if (NULL != s_pBootModuleMgr) {
        s_pBootModuleMgr->Release();
        s_pBootModuleMgr = NULL;
    }
}

extern "C"  IDeviceDriver * GetBootModuleMgrDriver()
{
    assert(NULL != s_pBootModuleMgr);
    return s_pBootModuleMgr;
}

